package net.anjingnorak.javabase.model;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.table.AbstractTableModel;

/**
 * DataTable ini berfungsi sebagai tempat penyimpanan data dari database yang mempunyai turunan class 
 * dari Abstract Table Model sehinggal bisa langsung digunakan di dalam JTable
 * 
 * @author Gian Rishandy
 *
 */
public class DataTable extends AbstractTableModel {

	private static final long serialVersionUID = -6438734695335125597L;
	private List<DataColumn> dataColumns;
	private List<DataRow> dataRows;
	private Integer dataTableType;
	private String[] disableColumns;
	
	public static int Viewer = 0;
	public static int Transaction = 1;
	
	public DataTable() {
		dataColumns = new ArrayList<DataColumn>();
		dataRows = new ArrayList<DataRow>();
		
		dataTableType = DataTable.Transaction;
	}
	
	public void setDatatable(ResultSet result) throws Exception{
		boolean loop = true;
		boolean empty = true;
		ResultSetMetaData meta = result.getMetaData();
		
		while (result.next()) {
			empty = false;
			DataRow datarow = new DataRow();
			int size = meta.getColumnCount();
			for(int i=0;i<size;i++){
				String columnName = meta.getColumnName(i+1);
				int columnType = meta.getColumnType(i+1);
				
				if(columnType == Types.DATE || columnType == Types.TIME || columnType == Types.TIMESTAMP){
					datarow.add(result.getDate(columnName));
				}else{
					datarow.add(result.getObject(columnName));
				}
				
				if(loop){
					DataColumn datacolumn = new DataColumn();
					datacolumn.setColumnName(columnName);
					
					if(columnType == Types.VARCHAR || columnType == Types.CHAR || columnType == Types.NVARCHAR){
						datacolumn.setColumnClass(String.class);
					}else if(columnType == Types.INTEGER || columnType == Types.BIGINT || columnType == Types.SMALLINT || columnType == Types.TINYINT){
						datacolumn.setColumnClass(Integer.class);
					}else if(columnType == Types.DECIMAL || columnType == Types.DOUBLE || columnType == Types.FLOAT || columnType == Types.NUMERIC){
						datacolumn.setColumnClass(BigDecimal.class);
					}else if(columnType == Types.DATE || columnType == Types.TIME || columnType == Types.TIMESTAMP){
						datacolumn.setColumnClass(Date.class);
					}else if(columnType == Types.BOOLEAN || columnType == Types.BIT){
						datacolumn.setColumnClass(Boolean.class);
					}else{
						datacolumn.setColumnClass(Object.class);
					}
					
					dataColumns.add(datacolumn);
				}
			}
			
			loop = false;
			dataRows.add(datarow);
		}
		
		if(empty){
			int size = meta.getColumnCount();
			for(int i=0;i<size;i++){
				String columnName = meta.getColumnName(i+1);
				int columnType = meta.getColumnType(i+1);
				
				DataColumn datacolumn = new DataColumn();
				datacolumn.setColumnName(columnName);
				
				if(columnType == Types.VARCHAR || columnType == Types.CHAR || columnType == Types.NVARCHAR){
					datacolumn.setColumnClass(String.class);
				}else if(columnType == Types.INTEGER || columnType == Types.BIGINT || columnType == Types.SMALLINT || columnType == Types.TINYINT){
					datacolumn.setColumnClass(Integer.class);
				}else if(columnType == Types.DECIMAL || columnType == Types.DOUBLE || columnType == Types.FLOAT || columnType == Types.NUMERIC){
					datacolumn.setColumnClass(BigDecimal.class);
				}else if(columnType == Types.DATE || columnType == Types.TIME || columnType == Types.TIMESTAMP){
					datacolumn.setColumnClass(Date.class);
				}else if(columnType == Types.BOOLEAN || columnType == Types.BIT){
					datacolumn.setColumnClass(Boolean.class);
				}else{
					datacolumn.setColumnClass(Object.class);
				}
				
				dataColumns.add(datacolumn);
			}
		}
	}
	

	/**
	 *	Mengkloning DataTable menjadi dua
	 * 
	 *	@return DataTable 
	 */
	public DataTable clone(){
		DataTable datatable = new DataTable();
		List<DataRow> datarows = new ArrayList<DataRow>();
		List<DataColumn> datacolumns = new ArrayList<DataColumn>();
		
		for(int i=0;i<getRowCount();i++){
			DataRow datarow = new DataRow();
			DataRow ldatarow = getRow(i);
			
			for(int j=0;j<getColumnCount();j++){
				datarow.add(ldatarow.getObject(j));
				
				if(i == 0){
					DataColumn datacolumn = new DataColumn();
					DataColumn ldatacolumn = getColumn(j);
					
					datacolumn.setColumnName(ldatacolumn.getColumnName());
					datacolumn.setColumnClass(ldatacolumn.getColumnClass());
					
					datacolumns.add(datacolumn);
				}
			}
			datarows.add(datarow);
		}
		
		datatable.setDataColumns(datacolumns);
		datatable.setDataRows(datarows);
		datatable.setDisableColumns(disableColumns);
		return datatable;
	}
	
	/**
	 *	Menambahkan baris di dalam DataTable 
	 */
	public void addRow(){
		DataRow datarow = new DataRow();
		for(int i=0;i<getColumnCount();i++){
			DataColumn datacolumn = dataColumns.get(i);
			Class<?> columnClass = datacolumn.getColumnClass();
			if(columnClass == Boolean.class){
				datarow.add(false);
			}else{
				datarow.add(null);
			}
		}
		addRow(datarow);
	}
	
	/**
	 *	Setting jumlah baris di dalam DataTable
	 * 
	 *	@param newRow
	 */
	public void setRowCount(int newRow){
		int oldRow = getRowCount();
		if(oldRow > newRow){
			int row = oldRow - newRow;
			for(int i=0;i<row;i++){
				removeRow(getRowCount()-1);
			}
		}else if(oldRow < newRow){
			int row = newRow - oldRow;
			for(int i=0;i<row;i++){
				addRow();
			}
		}
	}
	
	/**
	 *	Menambah baris di dalam DataTable dengan parameter DataRow untuk isi dari baris tersebut
	 *  
	 *  @param datarow
	 */
	public void addRow(DataRow datarow){
		dataRows.add(datarow);
		fireTableRowsInserted(getRowCount(), getRowCount());
	}
	
	/**
	 * 	Menghapus baris dalam DataTable
	 * 
	 *  @param rowIndex
	 */
	public void removeRow(int rowIndex){
		dataRows.remove(rowIndex);
		fireTableRowsDeleted(rowIndex, rowIndex);
	}
	
	
	/**
	 * Menyisipkan baris dalam dataTable dengan parameter rowIndex sebagai baris mana yangakan disisipkan
	 * dan datarow sebagai isi dari baris tersebut
	 * 
	 * @param rowIndex
	 * @param datarow
	 */
	public void setRow(int rowIndex, DataRow datarow){
		dataRows.set(rowIndex, datarow);
		fireTableRowsUpdated(rowIndex, rowIndex);
	}
	
	
	/**
	 * Mengambil isi dari baris keberapa dalam bentuk DataRow
	 * 
	 * @param rowIndex
	 * @return DataRow
	 */
	public DataRow getRow(int rowIndex){
		DataRow datarow = dataRows.get(rowIndex);
		datarow.setColumns(dataColumns);
		return datarow;
	}
	
	/**
	 * Menambah kolom dalam DataTable
	 * 
	 * @param datacolumn
	 */
	public void addColumn(DataColumn datacolumn){
		dataColumns.add(datacolumn);
	}
	
	/**
	 * Menghapus kolom dalam DataTable
	 * 
	 * @param columnIndex
	 */
	public void removeColumn(int columnIndex){
		dataColumns.remove(columnIndex);
	}
	
	/**
	 * Menyisipkan kolom dalam DataTable
	 * 
	 * @param columnIndex
	 * @param datacolumn
	 */
	public void setColumn(int columnIndex, DataColumn datacolumn){
		dataColumns.set(columnIndex, datacolumn);
	}
	
	/**
	 * Mengambil isi dari kolom berupa DataColumn
	 * 
	 * @param columnIndex
	 * @return DataColumn
	 */
	public DataColumn getColumn(int columnIndex){
		return dataColumns.get(columnIndex);
	}

	@Override
	public int getRowCount() {
		return dataRows.size();
	}

	@Override
	public int getColumnCount() {
		return dataColumns.size();
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		return dataRows.get(rowIndex).get(columnIndex);
	}
	
	@Override
	public int findColumn(String columnName) {
		for(int i=0;i<getColumnCount();i++){
			DataColumn datacolumn = getColumn(i);
			String colName = datacolumn.getColumnName();
			if(colName.equalsIgnoreCase(columnName)){
				return i;
			}
		}
		return -1;
	}
	
	@Override
	public Class<?> getColumnClass(int columnIndex) {
		DataColumn datacolumn = getColumn(columnIndex);
		return datacolumn.getColumnClass();
	}
	
	@Override
	public String getColumnName(int column) {
		DataColumn datacolumn = getColumn(column);
		return datacolumn.getColumnName();
	}
	
	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		if(dataTableType == DataTable.Viewer){
			return false;
		}
		
		if(disableColumns != null){
			for(int i=0;i<disableColumns.length;i++){
				DataColumn datacolumn = getColumn(columnIndex);
				String columnName = datacolumn.getColumnName();
				if(disableColumns[i].equalsIgnoreCase(columnName)){
					return false;
				}
			}
		}
		return true;
	}
	
	@Override
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		dataRows.get(rowIndex).set(columnIndex, aValue);
		fireTableRowsUpdated(rowIndex, rowIndex);
	}
	
	public List<DataColumn> getDataColumns() {
		return dataColumns;
	}

	public void setDataColumns(List<DataColumn> dataColumns) {
		this.dataColumns = dataColumns;
	}

	public List<DataRow> getDataRows() {
		return dataRows;
	}

	public void setDataRows(List<DataRow> dataRows) {
		this.dataRows = dataRows;
	}

	public String[] getDisableColumns() {
		return disableColumns;
	}

	public void setDisableColumns(String[] disableColumns) {
		this.disableColumns = disableColumns;
	}

	public Integer getDataTableType() {
		return dataTableType;
	}

	public void setDataTableType(Integer dataTableType) {
		this.dataTableType = dataTableType;
	}
}
